
/*
 * Hlpay-Plus aggregate payment system. Copyright
 * (c) 2022-2023 Hlpay Team Copyright has the right of final interpretation.
 */

package com.hlkj.pay.service.admin.impl;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.hlkj.framework.caches.service.RedisTemplateService;
import com.hlkj.framework.common.pojo.LocalContext;
import com.hlkj.framework.common.pojo.LocalRequest;
import com.hlkj.framework.common.pojo.PageResult;
import com.hlkj.framework.common.provider.Aes256EncryptionProvider;
import com.hlkj.framework.common.util.collection.CollectionUtils;
import com.hlkj.framework.common.util.date.DateUtils;
import com.hlkj.framework.common.util.date.LocalDateTimeUtils;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.framework.common.util.web.WebFrameworkUtils;
import com.hlkj.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.hlkj.framework.mybatis.core.query.QueryWrapperX;
import com.hlkj.framework.mybatis.core.utils.MyBatisUtils;
import com.hlkj.pay.common.constants.AdminRedisConstant;
import com.hlkj.pay.dto.LocalAdminUserRequest;
import com.hlkj.pay.dto.admin.AdminUserDto;
import com.hlkj.pay.dto.admin.AdminUserQueryDto;
import com.hlkj.pay.dto.merchant.MerchantInfoRegisterDto;
import com.hlkj.pay.enums.AdminUserEnum;
import com.hlkj.pay.enums.CommonEnum;
import com.hlkj.pay.infrastructure.mapper.admin.AdminUserMapper;
import com.hlkj.pay.infrastructure.mapper.admin.UserRoleMappingMapper;
import com.hlkj.pay.infrastructure.model.admin.AdminUserDO;
import com.hlkj.pay.infrastructure.model.admin.AdminUserRoleMappingDO;
import com.hlkj.pay.infrastructure.model.token.TokenSecretDO;
import com.hlkj.pay.service.CommonSnFilterService;
import com.hlkj.pay.service.admin.IAdminUserService;
import com.hlkj.pay.service.admin.IRoleService;
import com.hlkj.pay.service.token.ITokenService;
import com.hlkj.pay.util.UserUtil;

import cn.hutool.extra.servlet.ServletUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author HlpayTeam
 * @date 2024/09/01 15:14
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class AdminUserServiceImpl extends CommonSnFilterService implements IAdminUserService {

    private final AdminUserMapper adminUserMapper;

    private final UserRoleMappingMapper userRoleMappingMapper;

    private final RedisTemplateService redisTemplateService;

    private final Aes256EncryptionProvider aes256EncryptionProvider;

    private final IRoleService roleService;

    private final ITokenService tokenService;

    @Value("${role.merchant.merchant:R0000002}")
    private String merchantRoleRegister;

    @Value("${role.agent.register:R0000004}")
    private String agentRoleRegister;

    @Value("${role.merchant.root:R0000003}")
    private String merchantRoleRoot;

    @Override
    public PageResult<AdminUserDto> queryUserPage(AdminUserQueryDto adminUserQueryDto) {
        filterSn(adminUserQueryDto);
        QueryWrapper<AdminUserDto> queryWrapper = buildUserQueryWrapper(adminUserQueryDto);
        IPage<AdminUserDto> mpPage = MyBatisUtils.buildPage(adminUserQueryDto);
        adminUserMapper.selectUserPage(mpPage, queryWrapper);
        return new PageResult(mpPage.getRecords(), mpPage.getTotal(), mpPage.getCurrent(), mpPage.getSize(), mpPage.getPages());

    }

    @Override
    public List<AdminUserDto> queryUserList(AdminUserQueryDto adminUserQueryDto) {
        filterSn(adminUserQueryDto);
        QueryWrapper<AdminUserDto> queryWrapper = buildUserQueryWrapper(adminUserQueryDto);
        return adminUserMapper.selectUserList(queryWrapper);
    }

    @Override
    public List<AdminUserDO> queryUserList(List<Long> userIds) {
        AdminUserQueryDto adminUserQueryDto = new AdminUserQueryDto();
        adminUserQueryDto.setUserIds(userIds);
        return adminUserMapper.selectList(buildWrapper(adminUserQueryDto));
    }

    @Override
    public List<AdminUserRoleMappingDO> queryUserRoles(Long userId) {
        AdminUserQueryDto adminUserQueryDto = new AdminUserQueryDto();
        adminUserQueryDto.setUserId(userId);
        return selectUserRoleList(adminUserQueryDto);
    }

    @Override
    public AdminUserDto queryUserDto(Long userId) {
        String userKey = userRedisKey(userId);
        String object = (String) redisTemplateService.get(userKey);
        if (object != null) {
            if (log.isDebugEnabled()) {
                log.debug("adminUserDto cache userId:{}", userId);
            }
            return JsonUtils.parseObject(object, AdminUserDto.class);
        }
        AdminUserDto adminUserDto = userDetail(userId);
        if (adminUserDto == null) {
            return null;
        }
        redisTemplateService.set(userKey, JsonUtils.toJsonString(adminUserDto), AdminRedisConstant.USER_INFO_EXPIRE_TIME);
        return adminUserDto;
    }

    @Override
    public Long addUser(AdminUserDO adminUserDO) throws Exception {
        adminUserDO.setUpdatePwdFlag(CommonEnum.YES_NO_TYPE.NO.getCode());
        adminUserDO.setInviteCode(inviteCode());
        adminUserMapper.insert(adminUserDO);
        return adminUserDO.getId();
    }

    @Override
    public void updateUser(AdminUserDO adminUserDO) throws Exception {
        adminUserMapper.updateById(adminUserDO);
        delUserRedisCache(adminUserDO.getId());
    }

    @Override
    public void deleteUser(Long userId) {
        adminUserMapper.deleteById(userId);
        delUserRedisCache(userId);
    }

    @Override
    public void assignUserRole(Long userId, List<String> roleCodes) {
        updateUserRoleCode(userId, roleCodes);
        delUserRedisCache(userId);
        addLoginStatusExpire(userId);
    }

    @Override
    public void updatePwd(Long userId, String pwd, CommonEnum.YES_NO_TYPE updatePwdFlag) throws Exception {
        updatePwd(userId, pwd, null, updatePwdFlag);
    }

    @Override
    public void updatePwd(Long userId, String pwd, Integer checkAgreement, CommonEnum.YES_NO_TYPE updatePwdFlag) throws Exception {
        AdminUserDO adminUserDO = new AdminUserDO();
        adminUserDO.setId(userId);
        adminUserDO.setPwdEncrypt(aes256EncryptionProvider.encryptString(pwd));
        adminUserDO.setUpdatePwdFlag(updatePwdFlag.getCode());
        if (checkAgreement != null) {
            adminUserDO.setCheckAgreement(adminUserDO.getCheckAgreement());
        }
        adminUserMapper.updateById(adminUserDO);
        delUserRedisCache(userId);
        addLoginStatusExpire(userId);
    }

    @Override
    public void updateLanguage(Long userId, String language) throws Exception {
        AdminUserDO adminUserDO = new AdminUserDO();
        adminUserDO.setId(userId);
        adminUserDO.setLanguage(language);
        adminUserMapper.updateById(adminUserDO);
        delUserRedisCache(userId);
    }

    @Override
    public void updateStatus(Long userId, Integer status) {
        AdminUserDO adminUserDO = new AdminUserDO();
        adminUserDO.setId(userId);
        adminUserDO.setStatus(status);
        adminUserMapper.updateById(adminUserDO);
        delUserRedisCache(userId);
        addLoginStatusExpire(userId);
    }

    @Override
    public boolean permissionChangeStatus() {
        Long loginUserId = LocalContext.get().getUserId();
        if (loginUserId == null) {
            return false;
        }
        return redisTemplateService.hasKey(permissionChangeKey(loginUserId));
    }

    @Override
    public void expirePermissionChangeStatus() {
        Long loginUserId = LocalContext.get().getUserId();
        String permissionChangeKey = permissionChangeKey(loginUserId.longValue());
        log.info("logInStatusKey tenantId:{},userId:{}", loginUserId);
        redisTemplateService.del(permissionChangeKey);
    }

    @Override
    public void delLogInUserCache() {
        Long loginUserId = LocalContext.get().getUserId();
        // 用户缓存
        delUserRedisCache(loginUserId);
        expirePermissionChangeStatus();
    }

    @Override
    public List<Long> roleChangeUser(String roleCode, Boolean delUserRoleRelation) {
        log.info("roleChangeUser tenantId:{},roleCode:{}", roleCode);
        AdminUserQueryDto adminUserQueryDto = new AdminUserQueryDto();
        adminUserQueryDto.setRoleCode(roleCode);
        adminUserQueryDto.setPageNo(1);
        adminUserQueryDto.setPageSize(1000);
        PageResult<AdminUserDto> pageResult = queryUserPage(adminUserQueryDto);
        List<AdminUserDto> adminUserDtoList = pageResult.getList();
        if (CollectionUtils.isEmpty(adminUserDtoList)) {
            return Collections.emptyList();
        }
        List<Long> userIds = adminUserDtoList.stream().map(AdminUserDto::getId).collect(Collectors.toList());
        if (delUserRoleRelation != null && delUserRoleRelation) {
            delUserRoleCode(userIds, roleCode);
        }
        log.info("roleChangeUser tenantId:{},userIds:{}", userIds);
        List<String> keys = new ArrayList<>(userIds.size());
        userIds.stream().forEach(userId -> {
            addLoginStatusExpire(userId);
            // 用户缓存 对应的角色信息有变更
            keys.add(userRedisKey(userId));
        });
        batchDelUserRedisCache(userIds);
        return userIds;
    }

    @Override
    public void addMerchantUser(MerchantInfoRegisterDto merchantInfoRegisterDto) {
        AdminUserDO adminUserDO = new AdminUserDO();
        try {
            if (!org.springframework.util.StringUtils.hasText(merchantInfoRegisterDto.getPwd())) {
                merchantInfoRegisterDto.setPwd(UserUtil.password());
            }
            adminUserDO.setPwdEncrypt(aes256EncryptionProvider.encryptString(merchantInfoRegisterDto.getPwd()));
            adminUserDO.setPhoneEncrypt(aes256EncryptionProvider.encryptString(merchantInfoRegisterDto.getPhone()));
        }
        catch (Exception e) {
            log.error(e.getMessage());
        }
        adminUserDO.setUserName(merchantInfoRegisterDto.getAccount());
        adminUserDO.setName(merchantInfoRegisterDto.getName());
        adminUserDO.setStatus(AdminUserEnum.USER_STATUS.ABLE.getCode());
        adminUserDO.setMultipointLogin(CommonEnum.YES_NO_TYPE.YES.getCode());
        adminUserDO.setSn(merchantInfoRegisterDto.getSn());
        adminUserDO.setSysType(merchantInfoRegisterDto.getSysType().getCode());
        adminUserDO.setCheckAgreement(merchantInfoRegisterDto.getCheckAgreement());
        adminUserDO.setInviteCode(inviteCode());
        adminUserMapper.insert(adminUserDO);
        // 新增默认管理员角色
        // RoleDO roleDO = new RoleDO();
        // roleDO.setName(merchantInfoRegisterDto.getAccount() + "管理员");
        // roleDO.setDescription("管理员角色");
        // roleDO.setSuperAdminFlag(Boolean.TRUE);
        // roleDO.setSysType(adminUserDO.getSysType());
        // roleDO.setSn(adminUserDO.getSn());
        // roleService.addRole(roleDO);
        // 新增角色与用户之间映射关系
        AdminUserRoleMappingDO adminUserRoleMappingDO = new AdminUserRoleMappingDO();
        switch (merchantInfoRegisterDto.getSysType()) {
            case AGENT:
                adminUserRoleMappingDO.setRoleCode(agentRoleRegister);
                break;
            default:
                // 是商户注册 如果非商户平台 都是商户管理员角色 商户平台为商户注册角色
                LocalRequest localRequest = LocalContext.get();
                if (localRequest != null) {
                    switch (CommonEnum.SYS_TYPE.from(localRequest.getSysType())) {
                        case MERCHANT:
                            adminUserRoleMappingDO.setRoleCode(merchantRoleRegister);
                            break;
                        default:
                            adminUserRoleMappingDO.setRoleCode(merchantRoleRoot);
                    }
                }
                else {
                    adminUserRoleMappingDO.setRoleCode(merchantRoleRegister);
                }
        }
        adminUserRoleMappingDO.setUserId(adminUserDO.getId());
        adminUserRoleMappingDO.setCreatedBy(adminUserDO.getId().intValue());
        userRoleMappingMapper.insert(adminUserRoleMappingDO);
    }

    @Override
    public void updateMerchantUserRole(String sn) {
        AdminUserDO adminUserDO = queryUserBySn(sn);
        if (adminUserDO == null) {
            log.warn("更新商户管理员角色失败,该商户下没有对应的用户sn:{}", sn);
            return;
        }
        AdminUserQueryDto adminUserQueryDto = new AdminUserQueryDto();
        adminUserQueryDto.setSn(sn);
        adminUserQueryDto.setRoleCode(merchantRoleRoot);
        adminUserQueryDto.setUserId(adminUserDO.getId());
        List<AdminUserRoleMappingDO> adminUserRoleMappingDOS = selectUserRoleList(adminUserQueryDto);
        if (!CollectionUtils.isEmpty(adminUserRoleMappingDOS)) {
            log.info("更新商户管理员角色成功,该商户下对应用户sn 已拥有商户管理员角色 sn:{},userId:{}", sn, adminUserDO.getId());
            return;
        }
        // 新增角色与用户之间映射关系
        AdminUserRoleMappingDO adminUserRoleMappingDO = new AdminUserRoleMappingDO();
        adminUserRoleMappingDO.setRoleCode(merchantRoleRoot);
        adminUserRoleMappingDO.setUserId(adminUserDO.getId());
        adminUserRoleMappingDO.setCreatedBy(adminUserDO.getId().intValue());
        userRoleMappingMapper.insert(adminUserRoleMappingDO);
        log.info("更新商户管理员角色成功,改商户下没有对应的用户sn:{},userId:{}", sn, adminUserDO.getId());
    }

    @Override
    public void updateUserTeams(List<Long> userIds, String teamsCode) {
        if (CollectionUtils.isEmpty(userIds)) {
            return;
        }
        adminUserMapper.updateUserTeams(userIds, teamsCode);
        batchDelUserRedisCache(userIds);
    }

    @Override
    public List<AdminUserDto> querySysUserList() {
        LocalRequest localRequest = LocalContext.get();
        AdminUserQueryDto adminUserQueryDto = new AdminUserQueryDto();
        adminUserQueryDto.setSysType(localRequest.getSysType());
        QueryWrapper<AdminUserDto> queryWrapper = buildUserQueryWrapper(adminUserQueryDto);
        return adminUserMapper.selectUserList(queryWrapper);
    }

    @Override
    public AdminUserDto queryUserByEmail(String email, Integer sysType) throws Exception {
        AdminUserQueryDto adminUserQueryDto = new AdminUserQueryDto();
        adminUserQueryDto.setEmailEncrypt(aes256EncryptionProvider.encryptString(email));
        if (sysType == null) {
            LocalRequest localRequest = LocalContext.get();
            if (localRequest != null) {
                LocalAdminUserRequest adminUserRequest = (LocalAdminUserRequest) localRequest;
                adminUserQueryDto.setSysType(adminUserRequest.getSysType());
            }
            else {
                TokenSecretDO tokenSecretDO = tokenService.queryTenantInfoByDomain();
                if (tokenSecretDO == null) {
                    return null;
                }
                adminUserQueryDto.setSysType(tokenSecretDO.getSysType());
            }
        }
        else {
            adminUserQueryDto.setSysType(sysType);
        }
        return queryOne(adminUserQueryDto);
    }

    // @Override
    // public AdminUserDto queryUserByPhone(String phone) throws Exception {
    // AdminUserQueryDto adminUserQueryDto = new AdminUserQueryDto();
    // // adminUserQueryDto.setPhoneEncrypt(phone);
    // adminUserQueryDto.setPhoneEncrypt(aes256EncryptionProvider.encryptString(phone));
    // LocalAdminUserRequest localAdminUserRequest = (LocalAdminUserRequest)
    // LocalContext.get();
    // if (localAdminUserRequest == null) {
    // TokenSecretDO tokenSecretDO = tokenService.queryTenantInfoByDomain();
    // if (tokenSecretDO == null) {
    // return null;
    // }
    // adminUserQueryDto.setSysType(tokenSecretDO.getSysType());
    // }
    // else {
    // adminUserQueryDto.setSysType(localAdminUserRequest.getSysType());
    // }
    // return queryOne(adminUserQueryDto);
    // }

    @Override
    public AdminUserDto queryUserByPhone(String phone, Integer sysType) throws Exception {
        AdminUserQueryDto adminUserQueryDto = new AdminUserQueryDto();
        // adminUserQueryDto.setPhoneEncrypt(phone);
        adminUserQueryDto.setPhoneEncrypt(aes256EncryptionProvider.encryptString(phone));
        if (sysType == null) {
            LocalRequest localRequest = LocalContext.get();
            if (localRequest != null) {
                LocalAdminUserRequest adminUserRequest = (LocalAdminUserRequest) localRequest;
                adminUserQueryDto.setSysType(adminUserRequest.getSysType());
            }
            else {
                TokenSecretDO tokenSecretDO = tokenService.queryTenantInfoByDomain();
                if (tokenSecretDO == null) {
                    return null;
                }
                adminUserQueryDto.setSysType(tokenSecretDO.getSysType());
            }
        }
        else {
            adminUserQueryDto.setSysType(sysType);
        }
        return queryOne(adminUserQueryDto);
    }

    @Override
    public AdminUserDto queryUserByAccount(String account) {
        AdminUserQueryDto adminUserQueryDto = new AdminUserQueryDto();
        adminUserQueryDto.setUserName(account);
        LocalRequest localAdminUserRequest = LocalContext.get();
        if (localAdminUserRequest == null) {
            TokenSecretDO tokenSecretDO = tokenService.queryTenantInfoByDomain();
            if (tokenSecretDO == null) {
                return null;
            }
            adminUserQueryDto.setSysType(tokenSecretDO.getSysType());
        }
        else {
            adminUserQueryDto.setSysType(localAdminUserRequest.getSysType());
        }
        return queryOne(adminUserQueryDto);
    }

    @Override
    public AdminUserDto queryUserByAccount(String account, Integer sysType) throws Exception {
        AdminUserQueryDto adminUserQueryDto = new AdminUserQueryDto();
        adminUserQueryDto.setUserName(account);
        adminUserQueryDto.setSysType(sysType);
        return queryOne(adminUserQueryDto);
    }

    @Override
    public AdminUserDO queryUserBySn(String sn) {
        AdminUserQueryDto adminUserQueryDto = new AdminUserQueryDto();
        adminUserQueryDto.setSn(sn);
        LambdaQueryWrapper<AdminUserDO> lambdaQueryWrapper = buildWrapper(adminUserQueryDto);
        lambdaQueryWrapper.orderByAsc(AdminUserDO::getId);
        lambdaQueryWrapper.last(" limit 1");
        return adminUserMapper.selectOne(lambdaQueryWrapper);
    }

    @Override
    public AdminUserDO queryUser(Long userId) {
        AdminUserQueryDto adminUserQueryDto = new AdminUserQueryDto();
        adminUserQueryDto.setUserId(userId);
        return selectOne(adminUserQueryDto);
    }

    @Override
    public void updateUserLoginTime(Long userId, Integer checkAgreement) {
        AdminUserDO adminUserDO = new AdminUserDO();
        adminUserDO.setLastLoginTime(LocalDateTimeUtils.datatimeToTimestamp(LocalDateTime.now()));
        adminUserDO.setCheckAgreement(checkAgreement);
        adminUserDO.setId(userId);
        HttpServletRequest request = WebFrameworkUtils.getRequest();
        adminUserDO.setLoginIp(ServletUtil.getClientIP(request, null));
        adminUserMapper.updateById(adminUserDO);
        delUserRedisCache(userId);
    }

    public AdminUserDto queryOne(AdminUserQueryDto adminUserQueryDto) {
        AdminUserDO adminUserDO = selectOne(adminUserQueryDto);
        return userDto(adminUserDO);
    }

    public List<AdminUserDO> queryList(AdminUserQueryDto adminUserQueryDto) {
        return adminUserMapper.selectList(buildWrapper(adminUserQueryDto));
    }

    AdminUserDto userDto(AdminUserDO adminUserDO) {
        if (adminUserDO == null) {
            return null;
        }
        AdminUserQueryDto adminUserQueryDto = new AdminUserQueryDto();
        adminUserQueryDto.setUserId(adminUserDO.getId());
        AdminUserDto adminUserDto = new AdminUserDto();
        BeanUtils.copyProperties(adminUserDO, adminUserDto);
        List<AdminUserRoleMappingDO> userRoleMappingList = selectUserRoleList(adminUserQueryDto);
        if (CollectionUtils.isEmpty(userRoleMappingList)) {
            userRoleMappingList = Collections.emptyList();
        }
        List<String> roleCodesBefore = userRoleMappingList.stream().map(AdminUserRoleMappingDO::getRoleCode).collect(Collectors.toList());
        adminUserDto.setRoleCodes(roleCodesBefore);
        return adminUserDto;
    }

    public AdminUserDto userDetail(Long userId) {
        AdminUserQueryDto adminUserQueryDto = new AdminUserQueryDto();
        adminUserQueryDto.setUserId(userId);
        AdminUserDO adminUserDO = selectOne(adminUserQueryDto);
        return userDto(adminUserDO);
    }

    /**
     * 清楚缓存
     * 
     * @param userId
     */
    void delUserRedisCache(Long userId) {
        if (userId == null) {
            return;
        }
        log.info("delUserRedisCache userId:{}", userId);
        String userRedisKey = userRedisKey(userId);
        if (redisTemplateService.hasKey(userRedisKey)) {
            redisTemplateService.del(userRedisKey);
        }
    }

    /**
     * 清楚缓存
     * 
     * @param userIds
     */
    void batchDelUserRedisCache(List<Long> userIds) {
        if (CollectionUtils.isEmpty(userIds)) {
            return;
        }
        log.info("delUserRedisCache tenantId:{},userIds:{}", userIds);
        List<String> userRedisKeys = new ArrayList<>(userIds.size());
        userIds.stream().forEach(userId -> {
            userRedisKeys.add(userRedisKey(userId));
        });
        redisTemplateService.del(userRedisKeys);
    }

    /**
     * 增加从新登录标记
     * 
     * @param userId
     */
    void addLoginStatusExpire(Long userId) {
        // 等级标记
        redisTemplateService.set(permissionChangeKey(userId), DateUtils.formatLocalDateTime(LocalDateTime.now()), AdminRedisConstant.LOGIN_STATUS_EXPIRE_TIME);
    }

    /**
     * user info cache key
     * 
     * @param userId
     * @return
     */
    private String userRedisKey(Long userId) {
        StringBuilder sb = new StringBuilder(AdminRedisConstant.USER_INFO);
        // sb.append(tenantId);
        sb.append(StringPool.COLON);
        sb.append(userId);
        return sb.toString();
    }

    /**
     * user log flag cache key
     * 
     * @param userId
     * @return
     */
    private String permissionChangeKey(Long userId) {
        StringBuilder sb = new StringBuilder(AdminRedisConstant.LOGIN_STATUS);
        // sb.append(tenantId);
        sb.append(StringPool.COLON);
        sb.append(userId);
        return sb.toString();
    }

    public void updateUserRoleCode(Long userId, List<String> roleCodesAfter) {
        // 先查出来用户已有的角色编码
        AdminUserQueryDto adminUserQueryDto = new AdminUserQueryDto();
        // adminUserQueryDto.setTenantId(tenantId);
        adminUserQueryDto.setUserId(userId);
        List<AdminUserRoleMappingDO> userRoleMappingList = selectUserRoleList(adminUserQueryDto);
        if (CollectionUtils.isEmpty(userRoleMappingList)) {
            userRoleMappingList = Collections.emptyList();
        }
        // 之前的code
        List<String> roleCodesBefore = userRoleMappingList.stream().map(AdminUserRoleMappingDO::getRoleCode).collect(Collectors.toList());
        // 之后有 之前没有 即新增的code
        List<String> addCodes = CollectionUtils.subtractToList(roleCodesAfter, roleCodesBefore);
        // 之后没有 之前有 即删除的code
        List<String> delCodes = CollectionUtils.subtractToList(roleCodesBefore, roleCodesAfter);
        log.info("updateUserRoleCode addCodes:{},delCodes:{}", JsonUtils.toJsonString(addCodes), JsonUtils.toJsonString(delCodes));

        // 新增的列表
        List<AdminUserRoleMappingDO> addUserRoleMappingList = new ArrayList<>(addCodes.size() * 3 / 2);
        addCodes.stream().forEach(addCode -> {
            AdminUserRoleMappingDO rolePermissionMapping = new AdminUserRoleMappingDO();
            rolePermissionMapping.setUserId(userId);
            rolePermissionMapping.setRoleCode(addCode);
            addUserRoleMappingList.add(rolePermissionMapping);
        });
        batchUpdateRolePermission(userId, delCodes, addUserRoleMappingList);
    }

    /**
     * 权限关系列表查询
     *
     * @param adminUserQueryDto
     * @return
     */
    List<AdminUserRoleMappingDO> selectUserRoleList(AdminUserQueryDto adminUserQueryDto) {
        LambdaQueryWrapper<AdminUserRoleMappingDO> buildPermissionWrapper = buildUserRoleWrapper(adminUserQueryDto);
        return userRoleMappingMapper.selectList(buildPermissionWrapper);
    }

    AdminUserDO selectOne(AdminUserQueryDto adminUserQueryDto) {
        LambdaQueryWrapper<AdminUserDO> wrapper = buildWrapper(adminUserQueryDto);
        wrapper.orderByDesc(AdminUserDO::getCreateTime);
        wrapper.last(" limit 1");
        return adminUserMapper.selectOne(wrapper);
    }

    /**
     * 权限关系列表查询
     *
     * @param adminUserQueryDto
     * @return
     */
    List<AdminUserDO> selectList(AdminUserQueryDto adminUserQueryDto) {
        LambdaQueryWrapper<AdminUserDO> buildWrapper = buildWrapper(adminUserQueryDto);
        return adminUserMapper.selectList(buildWrapper);
    }

    public void delUserRoleCode(List<Long> userIds, String roleCode) {
        AdminUserQueryDto adminUserQueryDto = new AdminUserQueryDto();
        // adminUserQueryDto.setTenantId(tenantId);
        adminUserQueryDto.setRoleCode(roleCode);
        adminUserQueryDto.setUserIds(userIds);
        // 删除
        userRoleMappingMapper.delete(buildUserRoleWrapper(adminUserQueryDto));
    }

    String inviteCode() {
        String inviteCode = UserUtil.inviteCode();
        AdminUserDO adminUserDO = adminUserMapper.selectOne(AdminUserDO::getInviteCode, inviteCode);
        if (adminUserDO == null) {
            return inviteCode;
        }
        return inviteCode();
    }

    @Transactional(rollbackFor = Exception.class)
    public void batchUpdateRolePermission(Long userId, List<String> delRoleCodes, List<AdminUserRoleMappingDO> addUserRoleMappingList) {
        if (CollectionUtils.isNotEmpty(addUserRoleMappingList)) {
            // 新增
            userRoleMappingMapper.insertBatch(addUserRoleMappingList);
        }
        if (CollectionUtils.isNotEmpty(delRoleCodes)) {
            AdminUserQueryDto adminUserQueryDto = new AdminUserQueryDto();
            // adminUserQueryDto.setTenantId(tenantId);
            adminUserQueryDto.setRoleCodes(delRoleCodes);
            adminUserQueryDto.setUserId(userId);
            // 删除
            userRoleMappingMapper.delete(buildUserRoleWrapper(adminUserQueryDto));
        }
    }

    /**
     * 查询条件封装
     *
     * @param adminUserQueryDto
     * @return
     */
    LambdaQueryWrapper<AdminUserDO> buildWrapper(AdminUserQueryDto adminUserQueryDto) {
        filterSn(adminUserQueryDto);
        LambdaQueryWrapperX<AdminUserDO> queryWrapper = new LambdaQueryWrapperX<>();
        queryWrapper.eqIfPresent(AdminUserDO::getPwdEncrypt, adminUserQueryDto.getPwdEncrypt());
        queryWrapper.eqIfPresent(AdminUserDO::getEmailEncrypt, adminUserQueryDto.getEmailEncrypt());
        queryWrapper.eqIfPresent(AdminUserDO::getPhoneEncrypt, adminUserQueryDto.getPhoneEncrypt());
        queryWrapper.inIfPresent(AdminUserDO::getId, adminUserQueryDto.getUserIds());
        queryWrapper.eqIfPresent(AdminUserDO::getId, adminUserQueryDto.getUserId());
        queryWrapper.eqIfPresent(AdminUserDO::getPartCode, adminUserQueryDto.getPartCode());
        queryWrapper.eqIfPresent(AdminUserDO::getSn, adminUserQueryDto.getSn());
        queryWrapper.inIfPresent(AdminUserDO::getSn, adminUserQueryDto.getSnList());
        queryWrapper.likeIfPresent(AdminUserDO::getSn, adminUserQueryDto.getLikeSn());
        queryWrapper.eqIfPresent(AdminUserDO::getUserName, adminUserQueryDto.getUserName());
        queryWrapper.likeIfPresent(AdminUserDO::getUserName, adminUserQueryDto.getLikeUserName());
        queryWrapper.eqIfPresent(AdminUserDO::getName, adminUserQueryDto.getName());
        queryWrapper.eqIfPresent(AdminUserDO::getSysType, adminUserQueryDto.getSysType());
        queryWrapper.likeIfPresent(AdminUserDO::getName, adminUserQueryDto.getLikeName());

        return queryWrapper;
    }

    /**
     * 查询条件封装
     *
     * @param adminUserQueryDto
     * @return
     */
    private LambdaQueryWrapper<AdminUserRoleMappingDO> buildUserRoleWrapper(AdminUserQueryDto adminUserQueryDto) {
        LambdaQueryWrapperX<AdminUserRoleMappingDO> queryWrapper = new LambdaQueryWrapperX<>();
        queryWrapper.eqIfPresent(AdminUserRoleMappingDO::getUserId, adminUserQueryDto.getUserId());
        queryWrapper.eqIfPresent(AdminUserRoleMappingDO::getRoleCode, adminUserQueryDto.getRoleCode());
        queryWrapper.inIfPresent(AdminUserRoleMappingDO::getUserId, adminUserQueryDto.getUserIds());
        queryWrapper.inIfPresent(AdminUserRoleMappingDO::getRoleCode, adminUserQueryDto.getRoleCodes());
        return queryWrapper;
    }

    private QueryWrapper<AdminUserDto> buildUserQueryWrapper(AdminUserQueryDto adminUserQueryDto) {
        filterSn(adminUserQueryDto);
        // LocalAdminUserRequest localAdminUserRequest = (LocalAdminUserRequest)
        // LocalContext.get();
        // adminUserQueryDto.setSn(localAdminUserRequest.getQuerySn());
        QueryWrapperX<AdminUserDto> queryWrapper = new QueryWrapperX<>();
        queryWrapper.eq("t1.delete_flag", 0);
        queryWrapper.eqIfPresent("t1.email_encrypt", adminUserQueryDto.getEmailEncrypt());
        queryWrapper.eqIfPresent("t1.phone_encrypt", adminUserQueryDto.getPhoneEncrypt());
        queryWrapper.eqIfPresent("t1.part_code", adminUserQueryDto.getPartCode());
        queryWrapper.likeIfPresent("t1.teams_code", adminUserQueryDto.getTeamsCode());
        queryWrapper.eqIfPresent("t1.status", adminUserQueryDto.getStatus());
        queryWrapper.likeIfPresent("t1.user_name", adminUserQueryDto.getUserName());
        queryWrapper.likeIfPresent("t1.name", adminUserQueryDto.getName());
        queryWrapper.likeIfPresent("t1.sn", adminUserQueryDto.getSn());
        queryWrapper.inIfPresent("t1.sn", adminUserQueryDto.getSnList());
        queryWrapper.eqIfPresent("t1.sys_type", adminUserQueryDto.getSysType());
        queryWrapper.eqIfPresent("t1.language", adminUserQueryDto.getLanguage());
        queryWrapper.eqIfPresent("t1.time_zone", adminUserQueryDto.getTimeZone());
        queryWrapper.eqIfPresent("t2.role_code", adminUserQueryDto.getRoleCode());
        queryWrapper.inIfPresent("t2.role_code", adminUserQueryDto.getRoleCodes());
        queryWrapper.likeIfPresent("t4.organization_name", adminUserQueryDto.getPartName());
        queryWrapper.groupBy("t1.id");
        if (StringUtils.isBlank(adminUserQueryDto.getSortingFields())) {
            queryWrapper.orderByDesc("t1.id");
        }
        return queryWrapper;

    }
}
